#include "control.hpp"
#include <SFML/Window/Event.hpp>

using namespace Shiny;

struct keysString
{
    sf::Keyboard::Key key;
    std::string       str;
};

keysString keyStrings[] =
{
    { sf::Keyboard::A,         "A"             },
    { sf::Keyboard::B,         "B"             },
    { sf::Keyboard::C,         "C"             },
    { sf::Keyboard::D,         "D"             },
    { sf::Keyboard::E,         "E"             },
    { sf::Keyboard::F,         "F"             },
    { sf::Keyboard::G,         "G"             },
    { sf::Keyboard::H,         "H"             },
    { sf::Keyboard::I,         "I"             },
    { sf::Keyboard::J,         "J"             },
    { sf::Keyboard::K,         "K"             },
    { sf::Keyboard::L,         "L"             },
    { sf::Keyboard::M,         "M"             },
    { sf::Keyboard::N,         "N"             },
    { sf::Keyboard::O,         "O"             },
    { sf::Keyboard::P,         "P"             },
    { sf::Keyboard::Q,         "Q"             },
    { sf::Keyboard::R,         "R"             },
    { sf::Keyboard::S,         "S"             },
    { sf::Keyboard::T,         "T"             },
    { sf::Keyboard::U,         "U"             },
    { sf::Keyboard::V,         "V"             },
    { sf::Keyboard::W,         "W"             },
    { sf::Keyboard::X,         "X"             },
    { sf::Keyboard::Y,         "Y"             },
    { sf::Keyboard::Z,         "Z"             },
    { sf::Keyboard::Num0,      "0"             },
    { sf::Keyboard::Num1,      "1"             },
    { sf::Keyboard::Num2,      "2"             },
    { sf::Keyboard::Num3,      "3"             },
    { sf::Keyboard::Num4,      "4"             },
    { sf::Keyboard::Num5,      "5"             },
    { sf::Keyboard::Num6,      "6"             },
    { sf::Keyboard::Num7,      "7"             },
    { sf::Keyboard::Num8,      "8"             },
    { sf::Keyboard::Num9,      "9"             },
    { sf::Keyboard::Numpad0,   "Numpad0"       },
    { sf::Keyboard::Numpad1,   "Numpad1"       },
    { sf::Keyboard::Numpad2,   "Numpad2"       },
    { sf::Keyboard::Numpad3,   "Numpad3"       },
    { sf::Keyboard::Numpad4,   "Numpad4"       },
    { sf::Keyboard::Numpad5,   "Numpad5"       },
    { sf::Keyboard::Numpad6,   "Numpad6"       },
    { sf::Keyboard::Numpad7,   "Numpad7"       },
    { sf::Keyboard::Numpad8,   "Numpad8"       },
    { sf::Keyboard::Numpad9,   "Numpad9"       },
    { sf::Keyboard::Escape,    "Escape"        },
    { sf::Keyboard::LControl,  "Left Control"  },
    { sf::Keyboard::LShift,    "Left Shift"    },
    { sf::Keyboard::LAlt,      "Left Alt"      },
    { sf::Keyboard::LSystem,   "Left Super"    },
    { sf::Keyboard::RControl,  "Right Control" },
    { sf::Keyboard::RShift,    "Right Shift"   },
    { sf::Keyboard::RAlt,      "Right Alt"     },
    { sf::Keyboard::RSystem,   "Right Super"   },
    { sf::Keyboard::Menu,      "Menu"          },
    { sf::Keyboard::LBracket,  "["             },
    { sf::Keyboard::RBracket,  "]"             },
    { sf::Keyboard::Comma,     ","             },
    { sf::Keyboard::SemiColon, ";"             },
    { sf::Keyboard::Quote,     "'"             },
    { sf::Keyboard::Slash,     "/"             },
    { sf::Keyboard::BackSlash, "\\"            },
    { sf::Keyboard::Tilde,     "~"             },
    { sf::Keyboard::Dash,      "-"             },
    { sf::Keyboard::Equal,     "="             },
    { sf::Keyboard::Space,     "Space"         },
    { sf::Keyboard::Return,    "Return"        },
    { sf::Keyboard::Back,      "Backspace"     },
    { sf::Keyboard::Tab,       "Tabulation"    },
    { sf::Keyboard::PageUp,    "Page Up"       },
    { sf::Keyboard::PageDown,  "Page Down"     },
    { sf::Keyboard::End,       "End"           },
    { sf::Keyboard::Home,      "Home"          },
    { sf::Keyboard::Insert,    "Insert"        },
    { sf::Keyboard::Delete,    "Delete"        },
    { sf::Keyboard::Add,       "+"             },
    { sf::Keyboard::Subtract,  "-"             },
    { sf::Keyboard::Multiply,  "*"             },
    { sf::Keyboard::Divide,    "/"             },
    { sf::Keyboard::Left,      "Left"          },
    { sf::Keyboard::Right,     "Right"         },
    { sf::Keyboard::Up,        "Up"            },
    { sf::Keyboard::Down,      "Down"          },
    { sf::Keyboard::F1,        "F1"            },
    { sf::Keyboard::F2,        "F2"            },
    { sf::Keyboard::F3,        "F3"            },
    { sf::Keyboard::F4,        "F4"            },
    { sf::Keyboard::F5,        "F5"            },
    { sf::Keyboard::F6,        "F6"            },
    { sf::Keyboard::F7,        "F7"            },
    { sf::Keyboard::F8,        "F8"            },
    { sf::Keyboard::F9,        "F9"            },
    { sf::Keyboard::F10,       "F10"           },
    { sf::Keyboard::F11,       "F11"           },
    { sf::Keyboard::F12,       "F12"           },
    { sf::Keyboard::F13,       "F13"           },
    { sf::Keyboard::F14,       "F14"           },
    { sf::Keyboard::F15,       "F15"           },
    { sf::Keyboard::Pause,     "Pause"         }
};

std::string        Shiny::key2string(const sf::Keyboard::Key key)
{
    unsigned short iterator;

    for (iterator = 0 ; iterator < sf::Keyboard::KeyCount ; ++iterator)
    {
	if (keyStrings[iterator].key == key)
	    return (keyStrings[iterator].str);
    }
    return ("Unknown key");
}

sf::Keyboard::Key  Shiny::string2key(const std::string str)
{
    unsigned short iterator;

    for (iterator = 0 ; iterator < sf::Keyboard::KeyCount ; ++iterator)
    {
	if (keyStrings[iterator].str == str)
	    return (keyStrings[iterator].key);
    }
    return (sf::Keyboard::KeyCount);
}

/*
 * Control
 */
void Control::ProcedeJoystick(const sf::Event event)
{
    Observatory::Signal<const sf::Event>* toTrigger;

    switch (event.Type)
    {
    case sf::Event::JoystickButtonPressed:
	toTrigger = &Pressed;
	break ;
    case sf::Event::JoystickButtonReleased:
	toTrigger = &Released;
	break ;
    default:
	return ;
    }
    if (CompareJoystick(event))
	toTrigger->Emit(event);
}

void Control::ProcedeKeyboard(const sf::Event event)
{
    Observatory::Signal<const sf::Event>* toTrigger;

    switch (event.Type)
    {
    case sf::Event::KeyPressed:
	toTrigger = &Pressed;
	break ;
    case sf::Event::KeyReleased:
	toTrigger = &Released;
	break ;
    default:
	return ;
    }
    if (CompareKeyboard(event))
	toTrigger->Emit(event);
}

bool Control::CompareJoystick(const sf::Event event) const
{
    switch (event.Type)
    {
    case sf::Event::JoystickButtonPressed:
    case sf::Event::JoystickButtonReleased:
	return (_event.JoystickButton.JoystickId == event.JoystickButton.JoystickId &&
		_event.JoystickButton.Button     == event.JoystickButton.Button);
    default:
	break ;
    }
    return (false);
}

bool Control::CompareKeyboard(const sf::Event event) const
{
    switch (event.Type)
    {
    case sf::Event::KeyPressed:
    case sf::Event::KeyReleased:
	return (_event.Key.Code == event.Key.Code);
    default:
	break ;
    }
    return (false);
}

/*
 * Controls
 */
void     Controls::LoadData(Data data)
{
    Data::iterator it  = data.begin();
    Data::iterator end = data.end();

    for (; it != end ; ++it)
    {
	Data control(*it);

	if (!(control["Key"].Nil()))
	  _controls.push_back(Control(control.Key(), string2key(control["Key"].Value())));
	else if (!(control["JoystickId"].Nil()))
	  _controls.push_back(Control(control.Key(), control["JoystickId"], control["JoystickButton"]));
    }
}

Control* Controls::operator[](const std::string& str)
{
    ControlList::iterator it = std::find(_controls.begin(), _controls.end(), str);

    return (it == _controls.end() ? 0 : &(*it));
}

void     Controls::operator()(const sf::Event event)
{
    if (_active)
    {
	ControlList::iterator it  = _controls.begin();
	ControlList::iterator end = _controls.end();

	for (; it != end ; ++it)
	  (*it)(event);
    }
}

/*
 * ControlManager
 */
bool ControlManager::ReceiveEvent(const sf::Event event)
{
    ControlWatchers::iterator it  = _watchers.begin();
    ControlWatchers::iterator end = _watchers.end();

    for (; it != end ; ++it)
      (**it)(event);
    DeleteWatchers();
}

void ControlManager::Add(Controls& controls)
{
    _watchers.push_back(&controls);
}

void ControlManager::Delete(Controls& controls)
{
    _toDel.push_back(&controls);
}

void ControlManager::DeleteWatchers(void)
{
    ControlWatchers::iterator it = _toDel.begin();

    while (it != _toDel.end())
    {
      _watchers.remove(*it);
      it = _toDel.erase(it);
    }
}
